import java.awt.Graphics;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.Vector;


public class TetrisShape {

	public static final int BLOCK_WIDTH = 30;
	public static final int BLOCK_HEIGHT = 30;
	
	public static final int SHAPE_ROWS = 4;
	public static final int SHAPE_COLS = 4;
	public static final boolean[][] shapeLong = {
	      { false, false, false, false },
	      { false, false, false, false },
	      { true,  true,  true,  true },
	      { false, false, false, false  }
	    };

	public static final boolean[][] shapeNubUp = {
	    { false, false, false, false },
	    { false, true, false, false },
	    { true,  true,  true,  false  },
	    { false, false, false, false }
	  };

	public static final boolean[][] shapeNubLeft = {
	    { false, false, false, false },
	    { false, false, false, false },
	    { true,  false, false, false },
	    { true,  true,  true,  false }
	  };

	public static final boolean[][] shapeNubRight = {
	    { false, false, false, false },
	    { false, false, false, false },
	    { false, false, true,  false },
	    { true,  true,  true,  false }
	  };
	
	public static final boolean[][][] shapeList = 
		{shapeLong, shapeNubUp, shapeNubLeft, shapeNubRight};
	
	private boolean[][] currentShape;
	
	private boolean isFalling;
	private Vector<BlockSprite> blockList;
	private ImagesLoader imsLd;
	private String name;
	private Rectangle gameBoard;
	
	private int shapeType;
	//0 = ____  1 = _|_  2 = ___| 3 = |___
	
	private int velocity = 1;
	//A multiplier for how fast the shape is moving downward, 0 = no movement
	
	private int loc_x, loc_y, oldPivot_x, oldPivot_y;
	private BlockDump blockDump;
	private int initLoc_x;
	//loc is at topleft corner, (width,height) is bottom right corner
	private int initLoc_y;
	
	public TetrisShape(int shapeType, Rectangle gameBoard, ImagesLoader imsLd, BlockDump bs, String name){
		loc_x = initLoc_x = gameBoard.x + BLOCK_WIDTH*6;
		loc_y = initLoc_y = gameBoard.y;
		this.shapeType = shapeType;
		this.gameBoard = gameBoard;
		this.imsLd = imsLd;
		this.name = name;
		isFalling = true;
		
		blockDump = bs;
		
		blockList = new Vector<BlockSprite>();
		initPivot();
		generateShape();
		initPosition();
		
	}
	
	private void initPivot() {
		// Sets up the Pivot for each shape type by utilizing the shapeType identifier
		//TODO Set up pivots for shapes other than Nub_left
		switch(shapeType){
			case 0:		oldPivot_x = 0;
						oldPivot_y = 0;break;
			//Straight Line Piece
			
			case 1:		oldPivot_x = 0;
						oldPivot_y = 0;break;
			//Nub in middle
			
			case 2:		oldPivot_x = 1;
						oldPivot_y = 3;
						System.out.println("shape Inited");
						break;
			//Nub on left
			
			case 3:		oldPivot_x = 3;
						oldPivot_y = 3;break;
			//Nub on right
		}
		
		
	}

	private void initPosition() {
		// TODO Auto-generated method stub
		
	}

	private void generateShape() {
		/*
	}
		if(shapeType < 4){
			for(int i=0; i<3; i++){
				//Lay down first 3 blocks that they all share
				addBlock(loc_x+i*BLOCK_WIDTH, loc_y);
				
			}
			switch(shapeType){
				case 0:		addBlock(loc_x+3*BLOCK_WIDTH, loc_y);break;
				//Straight Line Piece
				case 1:		addBlock(loc_x+BLOCK_WIDTH, loc_y-BLOCK_HEIGHT);break;
				//Nub in middle
				case 2:		addBlock(loc_x+2*BLOCK_WIDTH, loc_y-BLOCK_HEIGHT);break;
				//Nub on right
				case 3:		addBlock(loc_x, loc_y+BLOCK_HEIGHT);break;
				//Nub on left
			}
		}
		*/
		
		currentShape = shapeList[shapeType];
		loc_x = initLoc_x;
		loc_y = initLoc_y;
		velocity = 1;
		initPivot();
		generateFromMatrix(loc_x,loc_y);
		
	}

	private void generateFromMatrix(int x, int y) {
		for(int i = 0; i<SHAPE_ROWS; i++){ //rows (y)
			for(int j = 0 ; j<SHAPE_COLS; j++){  //column (x)
				if(currentShape[i][j]){
					addBlock(x+j*BLOCK_WIDTH, y+i*BLOCK_HEIGHT, j, i);
				}
			}
		}
		
	}

	private void addBlock(int x, int y, int matx, int maty) {
		blockList.add(new BlockSprite(x, y, matx, maty, imsLd, name, velocity));
	}

	public void updateShape() 
	  {
		loc_y += velocity;
	    for(BlockSprite block : blockList){
	    	block.updateSprite();
	    }
	    hasHitBlockDump();
	  }  // end of updateSprite()

	private void hasHitBlockDump() {
		boolean hit = false;
		BlockSprite hitBlock = null;
		int newBlockOffset = 0;
		for(BlockSprite block: blockList){
			hitBlock = blockDump.containsHit(block.getMyRectangle());
			//If we already hit the bottom...
			if(block.getYPosn() >= gameBoard.y + gameBoard.height -BLOCK_HEIGHT){
				hit = true;
				
				newBlockOffset = block.getYPosn()-(gameBoard.y + gameBoard.height-BLOCK_HEIGHT);
				break;
			}
			//If we hit a block
			else if(hitBlock != null ){
				hit = true;
				newBlockOffset = block.getYPosn()+BLOCK_HEIGHT-hitBlock.getYPosn();
				break;
			}
		}
		if(hit){
			for(BlockSprite block: blockList){
				block.setPosition(block.getXPosn(), block.getYPosn()-newBlockOffset);
				blockDump.add(block);
			}
			blockList = null;
			blockList = new Vector<BlockSprite>();
			generateShape();
		}
	}

	public void moveLeft() {
		boolean hitWall = false;
		for(BlockSprite block: blockList){
			if( block.getXPosn()-BLOCK_WIDTH < gameBoard.x ||
				blockDump.contains(block.getMyRectangle(0-BLOCK_WIDTH, 0) )){
				hitWall = true;
				break;
			}
		}
		if(!hitWall){
			for(BlockSprite block: blockList){
				block.setPosition(block.getXPosn()-BLOCK_WIDTH, block.getYPosn());
			}
			loc_x -= BLOCK_WIDTH;
		}
	}

	public void moveRight() {
		boolean hitWall = false;
		for(BlockSprite block: blockList){
			if( !(block.getXPosn()+BLOCK_WIDTH < (gameBoard.x + gameBoard.width) ||
				blockDump.contains(block.getMyRectangle(BLOCK_WIDTH, 0) ))){
				hitWall = true;
				break;
			}
		}
		if(!hitWall){
			for(BlockSprite block: blockList){
				block.setPosition(block.getXPosn()+BLOCK_WIDTH, block.getYPosn());
			}
			loc_x += BLOCK_WIDTH;
		}
	}

	public void rotate() {
		boolean[][] revMatrix = new boolean[SHAPE_ROWS][SHAPE_COLS];
		boolean[][] rotatedMatrix = new boolean[SHAPE_ROWS][SHAPE_COLS];
		//Need to rotate the matrix 90 degrees (doing this the hard way)
		//First we reverse the elements in each row
		for(int i = 0; i<SHAPE_ROWS; i++){ //rows (y)
			for(int j = 0 ; j<SHAPE_COLS; j++){  //column (x)
				revMatrix[i][SHAPE_COLS-1-j] = currentShape[i][j];
			}
		}
		
		//Now we transpose the matrix
		for(int i = 0; i<SHAPE_ROWS; i++){ //rows (y)
			for(int j = 0 ; j<SHAPE_COLS; j++){  //column (x)
				rotatedMatrix[j][i] = revMatrix[i][j];
			}
		}
		
		int newPivotX = oldPivot_y;
		int newPivotY = (SHAPE_COLS-1)-oldPivot_x;
		int pivotShiftX = oldPivot_x - newPivotX;
		int pivotShiftY = oldPivot_y - newPivotY;
		oldPivot_x = newPivotX;
		oldPivot_y = newPivotY;
		loc_x = loc_x + pivotShiftX*BLOCK_WIDTH;
		loc_y = loc_y + pivotShiftY*BLOCK_HEIGHT;
		
		blockList.removeAllElements();
		
		currentShape = null;
		currentShape = rotatedMatrix;
		revMatrix = null;
		rotatedMatrix = null;
		generateFromMatrix(loc_x, loc_y);
		
	}

	public void mouseMove(int x) {
		// TODO Auto-generated method stub
		
	}

	public void drawShape(Graphics dbg) {
		for(BlockSprite block : blockList){
	    	block.drawSprite(dbg);
	    }
		
	}
	
	public void increaseSpeed(){
		velocity = 10;
		for(BlockSprite block: blockList){
			block.setStep(0, velocity);
		}
	}
	
}
